﻿using UnityEngine;
using System.Collections;
[RequireComponent(typeof(Camera))]
public class CameraController : MonoBehaviour
{
    const float error = 0.1f;
    const float lerpFactor = 0.5f;
    public Transform Target;
    [Range(0f, 0.8f)]
    public float YLimitFactor = 0.625f;
    [Range(0f, 0.6f)]
    public float XLimitFactor = 0.25f;
    [HideInInspector]
    public bool ApplyFollowX = true;
    [HideInInspector]
    public bool ApplyFollowY = true;
    [HideInInspector]
    public float MoveRangeXLeft = -10000f;
    [HideInInspector]
    public float MoveRangeXRight = 10000f;
    float forwardDir = 1f;

    public float XLeftEdge { get { return transform.position.x - xEdge; } }
    public float XRightEdge { get { return transform.position.x + xEdge; } }
    public float CurrentCameraSize { get { return camera.orthographicSize; } }
    new Camera camera;
    Rigidbody2D targetRigid2D;
    float xEdge;
    float xLimitOffest, yLimitOffest;

    Coroutine ylerpCoroutine;

    private void Awake()
    {
        ylerpCoroutine = null;
        camera = GetComponent<Camera>();
        SetFollowValue(camera.orthographicSize);
        targetRigid2D = Target.GetComponent<Rigidbody2D>();
    }
    //在改变摄像机orthographicSize或屏幕分辨率后使用
    public void SetFollowValue(float newSize)
    {
        camera.orthographicSize = newSize;
        xEdge = newSize * Screen.width / Screen.height;
        xLimitOffest = xEdge * XLimitFactor;
        yLimitOffest = newSize * YLimitFactor;
    }
    //因为刚体运动是在FixedUpdate中完成，所以摄像机跟随也要在FixedUpdate中完成，否则会出现画面不协调
    private void FixedUpdate()
    {   
        Vector3 lim = transform.position;
        //forwardDir = Mathf.Sign(targetRigid2D.velocity.x);
        forwardDir = 1;
        lim.x -= xLimitOffest * forwardDir;
        Vector3 offest = lim - Target.position;
        float absx = Mathf.Abs(offest.x);
        float absy = Mathf.Abs(offest.y);
        if (ApplyFollowY)
        {
            if (absy > yLimitOffest)
            {
                offest.y = Mathf.Lerp(offest.y, 0, Time.fixedDeltaTime * absy / yLimitOffest);
            }
        }
        if (ApplyFollowX)
        {
            if (XRightEdge >= MoveRangeXRight)
            {
                ApplyFollowX = false;
                offest.x -= XRightEdge - MoveRangeXRight; // 强制令XRightEdge=MoveRangeXRight
            }
            else if (XLeftEdge <= MoveRangeXLeft)
            {
                ApplyFollowX = false;
                offest.x -= XLeftEdge - MoveRangeXLeft;
            }
            else
            {
                offest.x = Mathf.Lerp(offest.x, 0, Time.fixedDeltaTime * absx / xLimitOffest);
            }
        }
        else
        {
            //到达某个边缘但是向反方向运动。
            if ((XLeftEdge <= MoveRangeXLeft && targetRigid2D.velocity.x > 0 && transform.position.x < Target.position.x) || (XRightEdge >= MoveRangeXRight && targetRigid2D.velocity.x < 0&& transform.position.x > Target.position.x))
            {
                ApplyFollowX = true;//到达中央位置才能解锁
                offest.x += forwardDir * Time.fixedDeltaTime;//确保在下一次FixedUpdate中ApplyFollowX不会被设置为false
            }
            
        }
        lim = Target.position + offest;
        lim.x += xLimitOffest * forwardDir;
        transform.position = lim;
    }
    IEnumerator YLerpToTarget()
    {
        float tary = transform.position.y - yLimitOffest;
        float offestY = Mathf.Abs(tary - Target.position.y);
        while (offestY > error)
        {
            tary = Mathf.Lerp(tary, Target.position.y, Time.fixedDeltaTime / Mathf.Min(lerpFactor, offestY));
            transform.position = new Vector3(transform.position.x, tary + yLimitOffest, transform.position.z);
            offestY = Mathf.Abs(tary - Target.position.y);
            yield return new WaitForSeconds(Time.fixedDeltaTime);
        }
        transform.position = new Vector3(transform.position.x, tary + yLimitOffest, transform.position.z);
        ApplyFollowY = true;
        ylerpCoroutine = null;
    }
    /// <summary>
    /// 强制令transform.position.y - yLimitOffest == Target.position.y，在Target跳上某一个高台时使用
    /// </summary>
    public void ForceCamBottomToTarget()
    {
        if (ylerpCoroutine == null)
        {
            ApplyFollowY = false;
            ylerpCoroutine = StartCoroutine(YLerpToTarget());
        }
    }
}
